﻿/**
 * Copyright (C) 2011 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NGuice.Inject.Binder;
using NGuice.Inject.Spi;
using NGuice.Inject.Matcher;
using System.Reflection;
using AopAlliance.Intercept;

namespace NGuice.Inject
{
    /// <summary>
    /// 收集用于创建一个Injector的配置信息（主要为bindings）的绑定器。NGuice提供此
    /// 绑定器对象给你的应用中的Module实现者，以便每一个实现者都能贡献他们自己的
    /// bindings和其他的注册
    /// ==NGuice Binding EDSL:==
    /// <code>
    /// Bind(typeof(ServiceImpl));
    /// 这种绑定声明不做任何事情，他仅仅将ServiceImpl类绑定到自己。他不会改变NGuice默认的行为。
    /// </code>
    /// <code>
    /// Bind(typeof(Service)).To(typeof(ServiceImpl));
    /// 如果Service实例没有绑定元特性，则他将被认为是ServiceImpl实例。他覆盖了在Service上的所有
    /// [ImplementedBy]、[ProvidedBy]元特性，这是因为当他们到达这些元特性点时NGuice已经移动到了
    /// ServiceImpl上
    /// </code>
    /// <code>
    /// Bind(typeof(Service)).ToProvider(typeof(ServiceProvider));
    /// 这种类型的绑定，ServiceProvider必须继承或实现Provider服务。这种绑定指示NGuice首先以规则的方式
    /// 为没有元特性注释的Service注入请求解析一个ServiceProvider实例，然后调用Provider.Get()来获取Service实例。
    /// 这里的Provider不是一个工厂，因为他总是创建它提供的每一个实例。尽管如此，这也是一个好的实践。当创建时，
    /// 你能够使用NGuice的Scope概念让NGuice为你工作
    /// </code>
    /// <code>
    /// Bind(typeof(Service)).AnnotatedWith(typeof(Red)).To(ServiceImpl));
    /// 类似于上面的绑定类型，但他仅仅应用在具有Red元特性的Service注入请求上。
    /// </code>
    /// <code>
    /// Bind(typeof(ServiceImpl)).In(typeof(Singleton)) | Bind(typeof(ServiceImpl)).In(Scopes.SINGLETON)
    /// 每一个这种声明将放置ServiceImpl到singleton单例范围中。NGuice将仅创建一个ServiceImpl实例并将
    /// 为所有这种类型的注入请求重复使用。
    /// 注意1：如果你使用之前介绍的绑定类型，则其他的实例将仍热可以使用。NGuice并不过分阻止你创建你的
    /// “单例”的多个实例。
    /// 注意2：以这种方式指定的scope范围将覆盖所有在ServiceImpl中的scope元特性
    /// </code>
    /// <code>
    /// Bind(new TypeLiteral&ltPaymentService&ltCreditCard>>() {}).To(typeof(CreditCardPaymentService));
    /// 这种特定的构造是绑定一个泛型参数类型的方式。他告诉NGuice如何为一个
    /// {@code PaymentService<CreditCard>}类型的元素兑现注入请求。类CreditCardPaymentService必须实现
    /// PaymentService<CreditCard>接口。NGuice当前不能绑定或注入一个通用类型，例如：Set<E>。所有类型化
    /// 参数都必须完全的指定
    /// </code>
    /// <code>
    /// Bind(typeof(Service)).ToInstance(new ServiceImpl()) | Bind(typeof(Service)).ToInstance(SomeLegacyRegistry.getService());
    /// 在这个例子中，你的模块本身而不是NGuice负责获取Serviceimpl实例，然后询问NGuice总是使用此单例来填充Service注入请求。
    /// 当Injector被创建时，他自动为此实例执行域和方法的注入，但所有ServiceImpl上的构造注入将被简单忽略。
    /// 注意：使用这种方式的结果是你不能控制的！
    /// </code>
    /// <code>
    /// BindConstant().AnnotatedWith(typeof(ServerHost)).To(args[0]);
    /// 构建常数绑定。常数注入必须总是使用元特性。当一个常数绑定的值为一个字符串时，他总是能转换为所有原始类型，也可以转换
    /// 为enum或Type类型。其他类型的转换可以通过使用ConvertToTypes(Matcher, TypeConverter)配置
    /// </code>
    /// <code>
    ///  red = typeof(MyModule).GetField("Red").GetAttribute(typeof(Color));
    ///  Bind(typeof(Service)).AnnotatedWith(red).To(typeof(RedService));
    ///  如果你的绑定元特性具有参数，你能够应用不同的绑定到你的元注释的不同的值。以上的例子就是应用一个原型特性到你的module
    ///  类中，因此你能读取这个特性实例并给定他到NGuice中
    /// </code>
    /// <code>
    ///   Bind(typeof(Service)).AnnotatedWith(Names.Named("blue")).To(typeof(BlueService));
    ///   这种方式使用NGuice.Inject.Name.Named的名称来提供一个标准元特性
    /// </code>
    /// <code>
    ///  Constructor<T> loneCtor = GetLoneCtorFromServiceImplViaReflection();
    ///   Bind(typeof(ServiceImpl)).ToConstructor(loneCtor);
    ///   这个例子中，我们直接告知NGuice构造器使用一个具体的类。这意味着我们不需要放置
    ///   元特性在构造器上来注入而使用提供的构造器注入。这对于你不能修改存在的源代码类是非常有用的
    /// </code>
    /// Binder中的其他方法例如BindScope、BindInterceptor、Install、RequestStaticInjection、AddError、CurrentStage、
    /// 都是绑定语法的一部分，你可以直接参考方法上的注释以了解更多信息
    /// </summary>
    public interface IBinder
    {
        /*if[AOP]*/
        /// <summary>
        /// 绑定方法拦截器到匹配指定与指定方法上，一个方法将在以下情况下拦截：
        /// 1. NGuice创建的具有拦截的方法的实例
        /// 2. 类不能为sealed，方法为虚拟方法
        /// 3. protected、public、internal方法
        /// </summary>
        /// <param name="classMatcher">方法拦截器将被应用的类,泛型参数为Type的超类</param>
        /// <param name="methodMatcher">方法拦截器将被应用的方法，泛型参数为MethodInfo的超类</param>
        /// <param name="interceptors">拦截器</param>
        void BindInterceptor(IMatcher classMatcher, IMatcher methodMatcher, params IMethodInterceptor[] interceptors);
       /*end[AOP]*/

        /// <summary>
        /// 绑定一个scope到一个元特性
        ///</summary>
        void BindScope<T>(IScope scope) where T: Attribute;

        /// <summary>
        /// 非泛型方法
        /// </summary>
        /// <param name="annotionType"></param>
        /// <param name="scope"></param>
        void BindScope(Type annotionType, IScope scope);

        ILinkedBindingBuilder<T> Bind<T>(Key<T> key);
        
        //IAnnotatedBindingBuilder<T> Bind<T>(TypeLiteral<T> typeLiteral);

        IAnnotatedBindingBuilder<T> Bind<T>();

        IAnnotatedConstantBindingBuilder BindConstant();

        /// <summary>
        /// Injector将注入给定对象的实例域与方法
        /// </summary>
        /// <typeparam name="T">参数化的类型</typeparam>
        /// <param name="type">实例类型</param>
        /// <param name="instance">请求成员将被注入的实例</param>
        void RequestInjection<T>(T instance);

        /// <summary>
        /// 请求指定实例注入域或方法
        /// </summary>
        void RequestInjectionForNoGeneric(object instance);
        
        /// <summary>
        /// Injector将在给定的类中注入静态域和方法
        /// </summary>
        void RequestStaticInjection(params Type[] types);
        
        /// <summary>
        /// 使用给定的模块配置更多的特定于模块的bindings
        /// </summary>
        void Install(IModule module);
        
        /// <summary>
        /// 获取当前的Stage
        /// </summary>
        Stage CurrentStage
        {
            get;
        }
        
        /// <summary>
        /// 记录将显示给用户的错误消息。他不同于抛出一个异常，这允许我们继续
        /// 配置Injector并发现更多错误，他可以使用参数插入到错误消息中
        /// </summary>
        void AddError(string message, params object[] arguments);
        
        /// <summary>
        /// 记录一个异常的详细信息，并提供给用户
        /// </summary>
        void AddError(Exception e);
        
        /// <summary>
        /// 添加一个错误消息
        /// </summary>
        void AddError(Message message);

        /// <summary>
        /// 获取用于给定注入类型的提供者，返回的提供者直到Injector被创建时才有效，
        /// 如果你在之前使用，将抛出MethodAccessException异常
        /// </summary>
        /// <typeparam name="T">提供实例的类型</typeparam>
        IProvider<T> GetProvider<T>();

        /// <summary>
        /// 获取用于给定注入key的提供者，返回的提供者直到Injector被创建时才有效，
        /// 如果你在之前使用，将抛出MethodAccessException异常
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        IProvider<T> GetProvider<T>(Key<T> key);

        /// <summary>
        /// 非泛型方法
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        IProvider GetProvider(Key key);

        /// <summary>
        /// 获取用于注入域或方法到指定类型中的成员注入器，返回的成员注入器直到主Injector被创建时才有效，
        /// 如果你在之前使用，将抛出MethodAccessException异常
        /// </summary>
        IMembersInjector<T> GetMembersInjector<T>();

        /// <summary>
        /// 非泛型方法，返回的成员注入器应该为泛型类，泛型参数类型为type类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        IMembersInjector GetMembersInjector(Type type);

        /// <summary>
        /// 绑定一个类型转换器。injector注入器将使用给定的转换器转换常数字符为匹配的类型
        /// 注意：匹配器为泛型对象，泛型参数为Type的超类型
        /// </summary>
        /// <param name="typeMatcher">转换器能够处理的类型的匹配器</param>
        void ConvertToTypes(IMatcher typeMatcher, ITypeConverter converter);

        /// <summary>
        /// 为可注入类型注册一个监听器。NGuice当他遭遇匹配给定匹配器的可注入类型时将通知监听器
        /// 注意：匹配器为泛型对象，泛型参数为Type的超类型
        /// </summary>
        void BindListener(IMatcher typeMatcher, ITypeListener listener);

        /// <summary>
        /// 返回一个绑定器，此绑定器使用source对象为配置错误作为引用位置，通常为StackFrame，但也能
        /// 是任意绑定的源，例如.config配置文件的路径
        /// </summary>
        /// <param name="source">描述源位置的任意对象</param>
        /// <returns>与此绑定器共享他的配置的绑定器</returns>
        IBinder WithSource(object source);

        /// <summary>
        /// 返回当指定调用代码时将忽略指定类型的绑定器，调用者的StackFrame将被用于定位配置错误的源
        /// </summary>
        /// <param name="classesToSkip">创建绑定行为的类库</param>
        /// <returns>与此绑定器共享他的配置的绑定器</returns>
        IBinder SkipSources(params Type[] classesToSkip);

        /// <summary>
        /// 创建一个bindings和其他配置的子环境。返回的绑定器能够在此子环境下添加和配置信息
        /// </summary>
        /// <returns>从此邦定器继承配置的绑定器。在返回的绑定器中暴露的配置仅对此绑定器可见</returns>
        /// <see cref="PrivateModule"/>
        IPrivateBinder NewPrivateBinder();

        /// <summary>
        /// 指示Injector注入器bingings必须按照在Module中的顺序列表注入。没有显式绑定在
        /// 一个模块中的类将不能被注入。通过一个链接的binding创建的绑定（Bind(typeof(Foo)).To(typeof(FooImpl))）
        /// 将被允许注入，但隐式的绑定（FooImpl）不能直接注入，除非也使用显式的绑定（Bind(typeof(FooImpl))）
        /// 如果显式的bindings被请求，工具仍然可以解析隐式的绑定（通过一个绑定链创建）但Binding.Provider将失败。
        /// 默认的，显式的bindings不是必须的。如果父injector注入器要求显式的绑定，则所有子注入器（在注入器中的私有模块）
        /// 也同样要求显式绑定，如果父注入器不要求显式绑定，一个子注入器或一个私有模块能够可选的声明他们自身要求显式绑定。
        /// 如果他们声明，这个行为将限制到他们自身以及他们的孩子，其他兄弟不会要求显式绑定。
        /// 如果父亲没有要求显式绑定但孩子要求，则在孩子中的一个链式绑定可能会添加一个JIT绑定到父亲中。孩子将不被允许直接
        /// 引用绑定目标，但父亲和其他孩子却可以直接引用绑定目标
        /// </summary>
        void RequireExplicitBindings();

        /// <summary>
        /// 当发现一个循环依赖时，阻止NGuice构造一个Proxy代理，默认的循环代理还是可用。如果父注入器使得循环代理失效，则
        /// 所有子注入器（父注入器中的私有模块）也同样失效循环代理。如果父注入器不失效循环代理，一个子注入器或私有模块
        /// 可选声明自身是否失效循环代理。如果他们失效，则失效行为将限制到他们自身以及他们的孩子，其他兄弟注入器将不会失效
        /// </summary>
        void DisableCircularProxies();
        
    }
}
